package com.lingyun.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.lingyun.common.exception.LyException;
import com.lingyun.common.exception.ServiceException;
import com.lingyun.common.exception.user.CaptchaException;
import com.lingyun.common.exception.user.CaptchaExpireException;
import com.lingyun.common.exception.user.UserNotFoundException;
import com.lingyun.common.exception.user.UserPasswordNotMatchException;
import com.lingyun.common.mapper.LyRoleMapper;
import com.lingyun.common.mapper.LyUserRoleMapper;
import com.lingyun.common.pojo.LyUser;
import com.lingyun.common.pojo.LyUserRole;
import com.lingyun.common.utils.ErrorCode;
import com.lingyun.common.utils.RegexVerification;
import com.lingyun.common.utils.StringUtils;
import com.lingyun.common.utils.jwt.JwtUtils;
import com.lingyun.common.utils.redis.RedisUtils;
import com.lingyun.common.mapper.LyUserMapper;
import com.lingyun.common.vo.*;
import com.lingyun.common.vo.user.UserAll;
import com.lingyun.common.vo.user.UserFrom;
import com.lingyun.common.vo.user.UserRegister;
import com.lingyun.common.vo.user.UserVagueQuery;
import com.lingyun.system.api.EmailService;
import com.lingyun.system.service.LyUserService;
import org.springframework.beans.BeanUtils;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * @author 没事别学JAVA
 * @since 2021-03-07 17:06:47
 */
@Service("lyUserService")
public class LyUserServiceImpl extends ServiceImpl<LyUserMapper, LyUser> implements LyUserService {

    @Resource
    LyUserMapper lyUsermapper;

    @Resource
    EmailService emailService;

    @Resource
    RedisUtils redisUtils;

    @Resource
    LyUserRoleMapper lyUserRolemapper;

    @Resource
    AuthenticationProvider authenticationProvider;

    @Resource
    JwtUtils jwtUtils;


    @Resource
    LyRoleMapper lyRoleMapper;


    /**
     * 邮箱注册-发送验证码
     */
    @Override
    public void SendEmailVerificationCode(String Email) throws LyException {

        /**
         * 邮箱验证
         * */
        if (!RegexVerification.validEmail(Email)) {
            throw new LyException("邮箱格式不正确！", ErrorCode.EMAIL_REGEX_VERIFICATION_FAILED);
        }
        /**
         * 构建验证码
         * */
        Integer code = new Random().nextInt(9000) + 1000;

        /**
         * 判断用户是否存在
         */
        Map<String, Object> params = new HashMap<>();
        params.put("userName", Email);
        List<LyUser> ArrListUser = lyUsermapper.getLyUserListByMap(params);
        if (StringUtils.isNotEmpty(ArrListUser)) {
            throw new LyException("用户已存在", ErrorCode.AUTH_USER_ALREADY_EXISTS);
        }

        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("<html>");
        stringBuffer.append("<body>");
        stringBuffer.append("<h1>");
        stringBuffer.append("欢迎注册凌云系统，您的验证码为：<a style=\"color: red\">" + code + "</a>,有效时间3分钟!（若本人无相关操作,请忽略本邮件）");
        stringBuffer.append("</h1>");
        stringBuffer.append("</body>");
        stringBuffer.append("</html>");
        System.out.println(stringBuffer);
        /**
         * 发送验证码
         * */
        emailService.Email(Email, stringBuffer.toString());

        /**
         * 存入redis中
         * */
        String key = "activation_mobile:" + Email;
        redisUtils.setCacheObject(key,code,60 * 3, TimeUnit.SECONDS);
    }

    /**
     * 注册-数据入库
     */
    @Override
    public void lyRegistered(UserRegister userRegisterVO) throws LyException {

        /**
         *  校验注册数据
         */
        if (StringUtils.isNull(userRegisterVO)) {
            throw new LyException("请传递参数！", ErrorCode.AUTH_PARAMETER_ERROR);
        }
        if (StringUtils.isEmpty(userRegisterVO.getUserName())) {
            throw new LyException("请传递邮箱！", ErrorCode.AUTH_PARAMETER_ERROR);
        }
        if (StringUtils.isEmpty(userRegisterVO.getNickName())) {
            throw new LyException("请传递用户昵称！", ErrorCode.AUTH_PARAMETER_ERROR);
        }
        if (StringUtils.isEmpty(userRegisterVO.getPassword())) {
            throw new LyException("请传递用户密码！", ErrorCode.AUTH_PARAMETER_ERROR);
        }
        if (StringUtils.isEmpty(userRegisterVO.getVerificationCode())) {
            throw new LyException("请传递验证码！", ErrorCode.AUTH_PARAMETER_ERROR);
        }
        /**
         * 邮箱验证
         * */
        if (!RegexVerification.validEmail(userRegisterVO.getUserName())) {
            throw new LyException("邮箱格式不正确！", ErrorCode.EMAIL_REGEX_VERIFICATION_FAILED);
        }
        /**
         * 判断用户是否存在
         */
        Map<String, Object> params = new HashMap<>();
        params.put("userName", userRegisterVO.getUserName());
        List<LyUser> lyUserList = lyUsermapper.getLyUserListByMap(params);
        if (StringUtils.isNotEmpty(lyUserList)) {
            throw new LyException("用户已存在！", ErrorCode.AUTH_USER_ALREADY_EXISTS);
        }
        /**
         *
         *验证数据库 密码是否有效
         *
         * */
        String key = "activation_mobile:" + userRegisterVO.getUserName();
        if (!redisUtils.exist(key)) {
            throw new LyException("验证码过期，请重新发送！", ErrorCode.EMAIL_VERIFICATION_CODE_INVALID);
        }
        /**
         *
         * 判断验证码是否正确
         *
         * */
        if (!redisUtils.get(key).equals(userRegisterVO.getVerificationCode())) {
            throw new LyException("验证码输入错误！", ErrorCode.EMAIL_VERIFICATION_CODE_INVALID);
        }
        /**
         * 构建用户信息
         * */
        LyUser lyUser = new LyUser();
        BeanUtils.copyProperties(userRegisterVO, lyUser);
        /**
         * 赋予激活状态  0正常 1停用
         **/
        lyUser.setUserStatus("0");
        /**
         * 赋予用户 默认性别 0男 1女 2未知
         * */
        lyUser.setUserSex("0");
        /**
         * 赋予用户类型 0系统用户 1注册用户
         * */
        lyUser.setUserType("0");
        /**
         * 赋予用户删除标志 0代表存在 2代表删除
         * */
        lyUser.setDelFlag("0");

        // 这是邮箱注册 所以账号就是邮箱
        lyUser.setUserEmail(lyUser.getUserName());

        // 密码加密  使用Security
        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String ss = passwordEncoder.encode(lyUser.getPassword());
        lyUser.setPassword(ss);

        /**
         * 数据入库
         * */
        lyUsermapper.addUser(lyUser);
        /**
         * 用户和校色关系便 添加
         * */
        LyUserRole lyUserRole = new LyUserRole();
        lyUserRole.setUserId(lyUser.getUserId());
        //默认用户角色为 普通角色
        lyUserRole.setRoleId(2L);

        lyUserRolemapper.add(lyUserRole);
    }

    /**
     * 登录--邮箱
     */
    @Override
    public String lyLogin(LoginFrom loginFrom, HttpServletRequest request) throws CaptchaExpireException, CaptchaException, UserPasswordNotMatchException, ServiceException, UserNotFoundException {

        validateCaptcha(loginFrom.getVerificationCode(),loginFrom.getKeyCode());

        Authentication authentication = null;

        try {
            authentication = authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(loginFrom.getUserName(), loginFrom.getPassword()));
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                throw new UserPasswordNotMatchException();
            } else if(e instanceof UsernameNotFoundException){
                throw new UserNotFoundException();
            }else {
                throw new ServiceException(e.getMessage());
            }
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        return jwtUtils.createToken(loginUser);
    }



    /**
     * 校验验证码
     * @param verificationCode     验证码
     * @param keyCode     唯一标识
     */
    public void validateCaptcha(String verificationCode, String keyCode) throws CaptchaExpireException, CaptchaException {
        String captcha = redisUtils.getCacheObject(keyCode);
        if(captcha == null){
            throw new CaptchaExpireException();
        }
        if(!verificationCode.equals(captcha)){
            throw new CaptchaException();
        }
        redisUtils.delete(keyCode);
    }



    /**
     * @param userVagueQueryVo 查询条件接口
     *                         用户全部查询
     * @return List
     */
    @Override
    public IPage<UserAll> getUserList(UserVagueQuery userVagueQueryVo) {
        QueryWrapper queryWrapper = new QueryWrapper();
        if (!StrUtil.hasEmpty(userVagueQueryVo.getNickName())) {
            queryWrapper.like("nick_name", userVagueQueryVo.getNickName());
        }
        if (!StrUtil.hasEmpty(userVagueQueryVo.getUserName())) {
            queryWrapper.like("user_name", userVagueQueryVo.getUserName());
        }
        if (!StrUtil.hasEmpty(userVagueQueryVo.getLoginIp())) {
            queryWrapper.like("user_id", userVagueQueryVo.getLoginIp());
        }
        queryWrapper.orderByAsc("user_id");
        Page<UserAll> page = new Page<>(userVagueQueryVo.getCurrent(), userVagueQueryVo.getSize());
        IPage<UserAll> iPage = lyUsermapper.getUserList(page, queryWrapper);
        return iPage;
    }

    @Transactional
    @Override
    public boolean addUser(UserFrom userFromVo) throws LyException {

        //邮箱验证
        if (!RegexVerification.validEmail(userFromVo.getUserEmail())) {
            throw new LyException("邮箱格式不正确！", ErrorCode.EMAIL_REGEX_VERIFICATION_FAILED);
        }
        // 判断用户是否存在
        Map<String, Object> params = new HashMap<>();
        params.put("userName", userFromVo.getUserName());
        List<LyUser> lyUserList = lyUsermapper.getLyUserListByMap(params);
        if (StringUtils.isNotEmpty(lyUserList)) {
            throw new LyException("用户已存在，请更换账号！", ErrorCode.AUTH_USER_ALREADY_EXISTS);
        }

        LyUser lyUser = new LyUser();
        lyUser.setUserName(userFromVo.getUserName());
        lyUser.setNickName(userFromVo.getNickName());
        lyUser.setUserType(userFromVo.getUserType());
        lyUser.setUserEmail(userFromVo.getUserEmail());
        lyUser.setPhonenumber(userFromVo.getPhonenumber());
        lyUser.setUserSex(userFromVo.getUserSex());
        lyUser.setAvatar(userFromVo.getAvatar());

        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String ss = passwordEncoder.encode(userFromVo.getPassword());
        lyUser.setPassword(ss);

        lyUser.setUserStatus(userFromVo.getUserStatus());
        lyUser.setDelFlag("0");

        //用户数据入库
        lyUsermapper.addUser(lyUser);
        //用户和角色关系入库
        Long[] roleids = userFromVo.getRoleIds();
        if (StringUtils.isNotNull(roleids)) {
            List<LyUserRole> lyUserRoleList = new ArrayList<LyUserRole>();
            for (Long roleid : roleids) {

                LyUserRole lyUserRole = new LyUserRole();
                lyUserRole.setUserId(lyUser.getUserId());
                lyUserRole.setRoleId(roleid);
                lyUserRoleList.add(lyUserRole);

            }

            if (lyUserRoleList.size() > 0) {
                lyUserRolemapper.addlist(lyUserRoleList);
            }
        }
        return true;
    }

    @Override
    public UserFrom selectUserById(Long userId) {
        return lyUsermapper.selectUserById(userId);
    }


    @Override
    public List<Long> getUserRole(Long userId) {
        return lyRoleMapper.getUserRole(userId);
    }

    @Override
    public Boolean updateUser(UserFrom userFromVo) {

        LyUser lyUser = new LyUser();
        lyUser.setUserId(userFromVo.getUserId());
        lyUser.setUserName(userFromVo.getUserName());
        lyUser.setNickName(userFromVo.getNickName());
        lyUser.setUserType(userFromVo.getUserType());
        lyUser.setUserEmail(userFromVo.getUserEmail());
        lyUser.setPhonenumber(userFromVo.getPhonenumber());
        lyUser.setUserSex(userFromVo.getUserSex());
        lyUser.setAvatar(userFromVo.getAvatar());
        lyUser.setUserStatus(userFromVo.getUserStatus());

        // 修改用户表
        lyUsermapper.updateUser(lyUser);

        // 删除原先的关系
        lyUserRolemapper.DeleteId(userFromVo.getUserId());
        // 用户和角色关系入库
        Long[] roleids = userFromVo.getRoleIds();
        if (StringUtils.isNotNull(roleids)) {
            List<LyUserRole> lyUserRoleList = new ArrayList<LyUserRole>();
            for (Long roleid : roleids) {
                LyUserRole lyUserRole = new LyUserRole();
                lyUserRole.setUserId(lyUser.getUserId());
                lyUserRole.setRoleId(roleid);
                lyUserRoleList.add(lyUserRole);
            }
            if (lyUserRoleList.size() > 0) {
                lyUserRolemapper.addlist(lyUserRoleList);
            }
        }
        return true;
    }



    /**
     * 导出用户Excel信息-也可添加条件
     * @param userVagueQueryVo 搜索的条件
     * @return
     */
    @Override
    public List<UserAll> userExportExcel(UserVagueQuery userVagueQueryVo) {
        QueryWrapper queryWrapper = new QueryWrapper();
        if (!StrUtil.hasEmpty(userVagueQueryVo.getNickName())) {
            queryWrapper.like("nick_name", userVagueQueryVo.getNickName());
        }
        if (!StrUtil.hasEmpty(userVagueQueryVo.getUserName())) {
            queryWrapper.like("user_name", userVagueQueryVo.getUserName());
        }
        if (!StrUtil.hasEmpty(userVagueQueryVo.getLoginIp())) {
            queryWrapper.like("user_id", userVagueQueryVo.getLoginIp());
        }
        queryWrapper.orderByAsc("user_id");
        return lyUsermapper.userExportExcel(queryWrapper);
    }


















}
